Skip to content

Conversation

@danny-beton-lrn
Copy link
Contributor

Summary

Adds comprehensive Data API support to the Ruby SDK, following the pattern established in the Node.js SDK.

Changes

Core Implementation

  • New DataApi class (lib/learnosity/sdk/request/data_api.rb)
    • request() - Make single authenticated Data API requests
    • request_iter() - Iterate through paginated responses (returns Enumerator)
    • results_iter() - Iterate through individual results across pages (returns Enumerator)
    • Automatic routing metadata headers: X-Learnosity-Consumer, X-Learnosity-Action, X-Learnosity-SDK

Rails Quickstart Integration

  • Added Data API demo to quickstart application
    • Controller: app/controllers/data_api_controller.rb
    • View: app/views/data_api/index.html.erb
    • Route: /data_api/index
    • Demonstrates all three iteration methods with live API calls

Ruby 2.6 Compatibility Fixes

  • Commented out spring and spring-watcher-listen gems (require Ruby 2.7+)
  • Added require 'logger' to config/boot.rb for Rails 6.1 compatibility
  • Updated README to document Ruby 2.6+ support

Testing

  • Unit tests: spec/learnosity/sdk/request/data_api_spec.rb
  • Integration tests: spec/integration/data_api_spec.rb
  • Example usage: examples/simple/data_api_example.rb

Documentation

  • Updated REFERENCE.md with Data API usage examples
  • Updated README.md with Ruby version compatibility notes

Testing

All existing tests pass. New tests added for Data API functionality.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds comprehensive Data API support to the Ruby SDK, enabling authenticated requests with automatic pagination and routing metadata headers. The implementation follows the Node.js SDK pattern and includes Ruby 2.6 compatibility fixes for the Rails quickstart application.

Key Changes:

  • New DataApi class with three iteration methods: request() for single requests, request_iter() for page iteration, and results_iter() for individual result iteration
  • Automatic routing metadata headers (X-Learnosity-Consumer, X-Learnosity-Action, X-Learnosity-SDK) added to all Data API requests
  • Ruby 2.6 compatibility fixes including commented-out gems requiring Ruby 2.7+ and logger initialization

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
lib/learnosity/sdk/request/data_api.rb Core DataApi class implementation with request signing, pagination, and metadata headers
lib/learnosity/sdk.rb Exports DataApi class for convenient access
spec/learnosity/sdk/request/data_api_spec.rb Unit tests for DataApi methods and error handling
spec/integration/data_api_spec.rb Integration tests for request signing and API version handling
examples/simple/data_api_example.rb Example demonstrating three iteration patterns
docs/quickstart/lrn-sdk-rails/app/controllers/data_api_controller.rb Rails controller demonstrating Data API usage
docs/quickstart/lrn-sdk-rails/app/views/data_api/index.html.erb View displaying Data API demo results
docs/quickstart/lrn-sdk-rails/config/routes.rb Added route for Data API demo
docs/quickstart/lrn-sdk-rails/config/boot.rb Added logger require for Ruby 2.6 compatibility
docs/quickstart/lrn-sdk-rails/Gemfile Commented out spring gems for Ruby 2.6 compatibility
docs/quickstart/lrn-sdk-rails/app/views/index/index.html.erb Added link to Data API demo
REFERENCE.md Documentation for DataApi class usage
README.md Updated with Ruby 2.6 compatibility notes and Data API references
ChangeLog.md Release notes for Data API feature and compatibility fixes

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

mock_adapter = lambda do |url, signed_request, headers|
expect(url).to eq('https://data.learnosity.com/v1/itembank/items')
expect(headers['X-Learnosity-Consumer']).to eq(config[:consumer_key])
expect(headers['X-Learnosity-Action']).to eq('get_/itembank/items')
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test verifies the derived action format but doesn't test the actual derivation logic with different endpoint structures. Consider adding tests that verify derive_action is called with the correct endpoint parameter.

Copilot uses AI. Check for mistakes.
# Verify security contains signature
security = JSON.parse(captured_request[:signed_request]['security'])
expect(security['signature']).to be_a(String)
expect(security['signature']).to start_with('$02$')
Copy link

Copilot AI Dec 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The hardcoded signature format '$02$' is a magic string. Consider extracting this to a constant or adding a comment explaining what '$02$' represents in the signature format.

Copilot uses AI. Check for mistakes.
@Learnosity Learnosity deleted a comment from Copilot AI Dec 16, 2025
Copy link
Collaborator

@anthony-murphy-lrn anthony-murphy-lrn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me!

http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = (uri.scheme == 'https')

request = Net::HTTP::Post.new(uri.request_uri, headers)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to think about get?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on the Learnosity Data API docs, it looks like the API always uses HTTP POST, even for "get" actions. The action parameter ('get', 'set', 'update', 'delete') isn't the HTTP method - it's a Learnosity-specific action type that goes in the request body.

def default_http_adapter(endpoint, signed_request, headers)
uri = URI.parse(endpoint)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = (uri.scheme == 'https')
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we be setting timeouts for the requests?

@danny-beton-lrn danny-beton-lrn merged commit 4bdec81 into master Dec 18, 2025
3 checks passed
@danny-beton-lrn danny-beton-lrn deleted the LRN-49154/feature/ruby_dataapi_update branch December 18, 2025 12:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants